package com.aleyn.router.parser

import android.app.Activity
import com.aleyn.router.LRouter
import com.aleyn.router.core.routerGson
import com.aleyn.router.inject.qualifier.sq

/**
 * @author : Aleyn
 * @date : 2023/07/23 : 23:41
 *
 * 默认的参数解析器。
 * 负责从 `Activity` 或 `Fragment` 的 `Bundle` 中提取和解析参数。
 */
object DefaultParamParser {

    /**
     * 解析基本数据类型和 String 类型的参数。
     *
     * @param target 目标对象，通常是 Activity 或 Fragment。
     * @param key 参数的键。
     * @param type 期望的参数类型。
     * @return 解析后的参数值，如果找不到或类型不匹配则返回 null。
     */
    @Suppress("UNCHECKED_CAST")
    fun <T> parseDefault(
        target: Any?,
        key: String,
        type: Class<T>,
    ): T? {
        val obj = getBundleAny(target, key)
        var value = obj as? T
        // 如果获取到的值是字符串，但期望类型是基本类型，则尝试转换
        if (obj is String && type.isPrimitive) {
            value = obj.toPrimitive(type) as? T
        }
        return value
    }

    /**
     * 解析任意类型的参数，支持 JSON 对象和依赖注入。
     *
     * @param T 期望的参数类型。
     * @param target 目标对象，通常是 Activity 或 Fragment。
     * @param key 参数的键。如果为空，则使用字段名作为键。
     * @param fieldName 字段名，用作备用键。
     * @return 解析后的参数值。优先从 Bundle 中解析 JSON，失败则尝试通过 LRouter 进行依赖注入。
     */
    inline fun <reified T> parseAny(target: Any?, key: String, fieldName: String): T? {
        val currentKey = key.ifBlank { fieldName }
        val json = getBundleAny(target, currentKey) as? String
        // 1. 尝试从 Bundle 中获取 JSON 字符串并反序列化
        if (!json.isNullOrBlank()) {
            return runCatching { routerGson.fromJson(json, T::class.java) }.getOrNull()
        }
        // 2. 如果 JSON 解析失败，则尝试通过 LRouter 进行依赖注入
        return if (key.isBlank()) {
            LRouter.get(T::class)
        } else {
            LRouter.get(T::class, sq(key))
        }
    }

    /**
     * 从目标对象的 Bundle 中获取指定键的值。
     *
     * @param target 目标对象 (Activity 或 Fragment)。
     * @param key 键。
     * @return 存储在 Bundle 中的值，如果不存在则返回 null。
     */
    @Suppress("DEPRECATION")
    fun getBundleAny(target: Any?, key: String): Any? {
        val bundle = when (target) {
            is Activity -> target.intent?.extras
            is androidx.fragment.app.Fragment -> target.arguments
            else -> null
        }
        return bundle?.get(key)
    }

}

/**
 * 将字符串转换为指定的基本数据类型。
 *
 * @param clazz 目标基本类型的 Class 对象。
 * @return 转换后的基本类型值，如果转换失败则返回 null。
 */
private fun String.toPrimitive(clazz: Class<*>): Any? {
    return try {
        when (clazz.kotlin.qualifiedName) {
            "kotlin.Byte" -> this.toByte()
            "kotlin.Short" -> this.toShort()
            "kotlin.Int" -> this.toInt()
            "kotlin.Long" -> this.toLong()
            "kotlin.Float" -> this.toFloat()
            "kotlin.Double" -> this.toDouble()
            "kotlin.Boolean" -> this.toBoolean()
            "kotlin.Char" -> this.firstOrNull()
            else -> this
        }
    } catch (_: Throwable) {
        null
    }
}